/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/***********************************************************************
 *
 * FILENAME:
 * myStripChart.c
 *
 * PURPOSE:
 *   Provide a moving strip chart for the user.
 *
 * CREATED:
 *
 *
 * LAST MODIFIED:
 * $Author: dixonc $
 * $Date: 2005/07/13 20:34:40 $
 * $Revision: 1.8 $
 *
 ***********************************************************************/

#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <float.h>

#include "myStripChart.h"
#include "vcConfig.h"

#define FRAME_WIDTH 1

extern bool verbose;
extern GuiStruct guiStr;

//-- for color ideas, see  /usr/share/X11/rgb.txt
const gchar *DefaultDataColors[MAX_NUM_DATA_SETS] = {
	"red",
	"medium blue",
	"green",
	"firebrick",
	"yellow",
	"navy blue",
	"sea green",
	"light blue",
	"khaki",
	"light blue"
};

static int graphCount     = 0;
static GList *object_list = NULL;

void prefs_dialog_apply_to_all(GtkDialog *dialog);

/* Redraws the backing pixmap for the load graph and updates the window */
void gtkstripchart_draw (GtkStripChart *g)
{
	guint i, j;
	gint dely;

	if (!g->disp->window || !g->draw) 
		return;

	// make sure table legend is in proper state before we draw
	gtkstripchart_set_legend_table_draw (g, g->draw_legend_table);

	g->draw_width = g->disp->allocation.width - 2 * FRAME_WIDTH;
	g->draw_height = g->disp->allocation.height - 2 * FRAME_WIDTH;

	if (!g->pixmap)
		g->pixmap = gdk_pixmap_new (g->disp->window,
				g->draw_width, g->draw_height,
				gtk_widget_get_visual (g->disp)->depth);

	// Create GC if necessary. 
	if (g->gc == NULL) {
		g->gc = gdk_gc_new (g->disp->window);
		gdk_gc_copy (g->gc, g->disp->style->white_gc);
	}

	// Allocate colors.
	if (!g->colors_allocated) {
		GdkColormap *colormap;

		colormap = gdk_window_get_colormap (g->disp->window);
		for (i = 0; i < g->num_sets + 2; i++) {
			gdk_color_alloc (colormap, &(g->colors [i]));
		}

		g->colors_allocated = 1;
	}

	// Erase Rectangle 
	gdk_gc_set_foreground (g->gc, &(g->colors [0]));
	gdk_draw_rectangle (g->pixmap,
			g->gc,
			TRUE, FRAME_WIDTH, FRAME_WIDTH,
			g->disp->allocation.width - FRAME_WIDTH,
			g->disp->allocation.height - FRAME_WIDTH);

	// draw frame 
	gdk_gc_set_foreground (g->gc, &(g->colors [1]));
	gdk_draw_rectangle (g->pixmap,
			g->gc,
			FALSE, 0, 0,
			g->disp->allocation.width - 1 * FRAME_WIDTH,
			g->disp->allocation.height - 1 * FRAME_WIDTH);

	// draw 4 horizontal scale lines 
	dely = g->draw_height / 5;
	gint y1;
	gint x1;
	for (i = 1; i <5; i++) {
		y1 = g->draw_height + FRAME_WIDTH + 1 - i * dely;
		gdk_draw_line (g->pixmap, g->gc,
				FRAME_WIDTH, y1,  g->draw_width, y1);
	}

	/* determine max and min data values */
	float max = -INFINITY;
	float min =  INFINITY;
	unsigned int ii,jj;
	for (ii = g->num_points - 1; ii > 0; ii--) {
		for(jj=0; jj < g->num_sets; jj++) {
			if( g->data[ii][jj] == g->data[ii][jj] ) { // check to make sure not NAN
				if( g->data[ii][jj] > max) max = g->data[ii][jj];
				if( g->data[ii][jj] < min) min = g->data[ii][jj];
			}
		}
	}
	if( max == min ) {
		max += 1;
		min -= 1;
	}

	switch( g->config.axisMode ) {
		/* do this if you want to the max and min bounds to be over only data shown in the plot */
		case AUTO_SCALE_VISIBLE: default:
			g->maxVal = max;
			g->minVal = min;
			break;
			/* do this if you want to the max and min bounds to be over all data */
		case AUTO_SCALE_ALL:
			if( g->maxVal < max ) g->maxVal = max;
			if( g->minVal > min ) g->minVal = min;
			break;
	}

	/* draw axis limits */
	char str[128];
	int strLen;

	if( g->font == NULL ) {
		g->font = gtk_style_get_font(g->main_widget->style);
	}
	int fontHeight = gdk_string_height(g->font, "ABC19");
	int fontWidth;

	// max-Y
	strLen = sprintf(str,"%.2g", g->maxVal);
	fontWidth = gdk_string_width(g->font, str);
	x1 =  g->draw_width - 1 - fontWidth; //FRAME_WIDTH + 1;
	y1 = FRAME_WIDTH + 1 + fontHeight;
	gdk_draw_text(g->pixmap, g->font, g->gc, x1, y1, str, strLen);

	// min-Y
	strLen = sprintf(str,"%.2g", g->minVal);
	fontWidth = gdk_string_width(g->font, str);
	x1 =  g->draw_width - 1 - fontWidth; //FRAME_WIDTH + 1;
	y1 = g->draw_height - FRAME_WIDTH - 1;
	gdk_draw_text(g->pixmap, g->font, g->gc, x1, y1, str, strLen);

	// min-X (time)
	float T = g->config.update_interval*NUM_GRAPH_POINTS / 1000.0f;
	strLen = sprintf(str,"-%.2f sec", T);
	y1 = g->draw_height - FRAME_WIDTH - 1;
	x1 = FRAME_WIDTH + 1;
	gdk_draw_text(g->pixmap, g->font, g->gc, x1, y1, str, strLen);

	/* Draw the data line */
	gdk_gc_set_line_attributes (g->gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER );

	float delx = (float)(g->draw_width) / ( g->num_points - 1);
	for (j = 0; j < g->num_sets; j++) {
		gdk_gc_set_foreground (g->gc, &(g->colors [j + 2]));

		for (i = 0; i < g->num_points - 1; i++) {

			if ((g->data[i][j] == g->data[i][j] ) && (g->data[i+1][j] == g->data[i+1][j])) {
				gint x1 = (int)(i * delx );
				gint x2 = (int)((i + 1) * delx );
				gint y1 = (int)( (g->data[i][j]   - g->minVal) / (g->maxVal - g->minVal) * g->draw_height - FRAME_WIDTH );
				gint y2 = (int)( (g->data[i+1][j] - g->minVal) / (g->maxVal - g->minVal) * g->draw_height - FRAME_WIDTH );

				gdk_draw_line (g->pixmap, g->gc,
						g->draw_width - x2, g->draw_height - y2,
						g->draw_width - x1, g->draw_height - y1);
			}
			g->pos [i] -= (int)(g->data [i][j]);
		}
		g->pos[g->num_points - 1] -= (int)(g->data [g->num_points - 1] [j]);
	}

	gdk_gc_set_line_attributes (g->gc, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER );

	/* display legend */
	if(g->draw_legend) {
		for(j = 0; j < g->num_sets; j++) {
			strLen = sprintf(str,"%s %s",g->dataNames[j], gtk_label_get_text(GTK_LABEL(g->label[j])) );
			gdk_gc_set_foreground (g->gc, &(g->colors [j + 2]));
			gdk_draw_text(g->pixmap, g->font, g->gc, 5, 5+fontHeight+(fontHeight + 3)*j, str, strLen);
		}
	}

	/* finally, draw the pixmap image */		
	gdk_draw_pixmap (g->disp->window,
			g->disp->style->fg_gc [GTK_WIDGET_STATE(g->disp)],
			g->pixmap,
			0, 0,
			0, 0,
			g->disp->allocation.width,
			g->disp->allocation.height);

}


void gtkstripchart_set_legend_draw (GtkStripChart *chart, int onOff)
{
	chart->draw_legend = onOff;
}
void gtkstripchart_set_legend_table_draw (GtkStripChart *chart, int onOff)
{
	//cout << "gtkstripchart_set_legend_table_draw" << endl;
	chart->draw_legend_table = onOff;

	if( chart->draw_legend_table)
		gtk_widget_show_all(chart->legendTable);
	else
		gtk_widget_hide_all(chart->legendTable);
}

	void
gtkstripchart_unalloc (GtkStripChart *g)
{
	unsigned int i;

	if (!g->allocated)
		return;

	for (i = 0; i < g->num_points; i++) {
		g_free (g->data [i]);
		g_free (g->odata [i]);
		g->data[i] = NULL;
		g->odata[i] = NULL;
	}

	g_free (g->data);
	g_free (g->odata);
	g_free (g->pos);

	g->pos   = NULL;
	g->data  = NULL;
	g->odata = NULL;

	if (g->pixmap) {
		gdk_pixmap_unref (g->pixmap);
		g->pixmap = NULL;
	}
	if( g->gc )
		g_object_unref(g->gc);

	g->allocated = FALSE;
}

	void
gtkstripchart_alloc (GtkStripChart *g)
{
	unsigned int i, j;

	if (g->allocated)
		return;

	g->data  = g_new0 (gfloat *, g->num_points);
	g->odata = g_new0 (gfloat *, g->num_points);
	g->pos   = g_new0 (guint, g->num_points);

	g->data_size = sizeof (gfloat) * g->num_sets;

	for (i = 0; i < g->num_points; i++) {
		g->data [i] = (gfloat*)g_malloc0 (g->data_size);
		g->odata [i] = (gfloat*)g_malloc0 (g->data_size);
	}

	for (j = 0; j < g->num_sets; j++) {
		for (i = 0; i < g->num_points; i++) {
			g->data [i][j] = NAN;
		}
	}

	g->allocated = TRUE;
}

	gint
gtkstripchart_configure (GtkWidget *widget, GdkEventConfigure *event, gpointer data_ptr)
{
	//printf("gtkstripchart_configure\n");
	GtkStripChart *c = (GtkStripChart *) data_ptr;

	if (!c->draw)
		return TRUE;

	if (c->pixmap) {
		gdk_pixmap_unref (c->pixmap);
		c->pixmap = NULL;
	}

	if (!c->pixmap)
		c->pixmap = gdk_pixmap_new (widget->window,
				widget->allocation.width,
				widget->allocation.height,
				gtk_widget_get_visual (c->disp)->depth);

	gdk_draw_rectangle (c->pixmap,
			widget->style->black_gc,
			TRUE, 0,0,
			widget->allocation.width,
			widget->allocation.height);
	gdk_draw_pixmap (widget->window,
			c->disp->style->fg_gc [GTK_WIDGET_STATE(widget)],
			c->pixmap,
			0, 0,
			0, 0,
			c->disp->allocation.width,
			c->disp->allocation.height);

	//gtk_widget_queue_draw(GTK_WIDGET(c->main_widget));
	gtkstripchart_draw (c);

	event = NULL;
	return TRUE;
}

	gint
gtkstripchart_expose (GtkWidget *widget, GdkEventExpose *event,
		gpointer data_ptr)
{
	GtkStripChart *g = (GtkStripChart *) data_ptr;
	//printf("gtkstripchart_expose \n");

	//printf("expose: window=%p disp->window=%p\n", widget->window,g->disp->window);
	gdk_draw_pixmap (widget->window,
			widget->style->fg_gc [GTK_WIDGET_STATE(widget)],
			g->pixmap,
			event->area.x, event->area.y,
			event->area.x, event->area.y,
			event->area.width, event->area.height);
	return FALSE;
}

	void
gtkstripchart_destroy (GtkStripChart *g)
{
	if( g == NULL ) return;

	gtkstripchart_stop (g);
	vc_config_save_chart(g);

	object_list = g_list_remove (object_list, g);

	if( g->main_widget )
		gtk_widget_destroy( g->main_widget );
	g->main_widget = NULL;

	for (unsigned int i=0; i < g->num_points; i++) {
		if( g->data && g->data[i] ) {
			g_free( g->data[i] );
			g->data[i] = NULL;
		}
		if( g->odata && g->odata[i] ) {
			g_free( g->odata[i] );
			g->odata[i] = NULL;
		}
	}
	g->num_points = 0;

	if( g->colors ) g_free(g->colors);
	if( g->data )   g_free( g->data );
	if( g->odata )  g_free( g->odata );
	if( g->pos )    g_free( g->pos );

	if( g->pixmap ) g_object_unref(g->pixmap);
	if( g->gc )     g_object_unref(g->gc);


	g->colors = NULL;
	g->data   = NULL;
	g->odata  = NULL;
	g->pos    = NULL;
	g->pixmap = NULL;
	g->gc     = NULL;

	g_free(g);
	g = NULL;

}

	void
gtkstripchart_destroy_cb (GtkWidget *widget, gpointer data_ptr)
{
	//printf("gtkstripchart_destroy_cb \n");
	GtkStripChart *g = (GtkStripChart *) data_ptr;

	gtkstripchart_destroy(g);

	return;
}

void gtkstripchart_destroyall()
{
	for(int i=0; i < gtkstripchart_num_charts(); i++) {
		GtkStripChart *g = (GtkStripChart*) g_list_nth_data( object_list, i);
		gtkstripchart_destroy (g);
	}

	g_list_free(object_list);
}

	GtkStripChart *
gtkstripchart_new (gint numDataSets, const gchar *nameArr[], void * setPtr[], int setType[], gchar *name)
{
	GtkStripChart *g;
	int i;

	// limit the number of data sets
	if( numDataSets > MAX_NUM_DATA_SETS )
		numDataSets = MAX_NUM_DATA_SETS;

	g                  = g_new0 (GtkStripChart, 1);
	g->index           = graphCount;
	g->num_sets        = numDataSets;
	g->num_points      = NUM_GRAPH_POINTS;
	g->colors          = g_new0 (GdkColor, g->num_sets + 2);
	g->maxVal          = NAN;
	g->minVal          = NAN;
	g->config.axisMode = AUTO_SCALE_VISIBLE,

	gconf_getChartConfig(g, name);

	if( g->config.update_interval < (int)(1000*GTKSTRIPCHART_MIN_UPDATE) )
		g->config.update_interval = (int)(1000*GTKSTRIPCHART_MIN_UPDATE);

	g->update_interval   = g->config.update_interval;
	g->draw_width        = g->config.width;
	g->draw_height       = g->config.height ;
	g->draw_legend       = g->config.draw_legend ;
	g->draw_legend_table = g->config.draw_legend_table ;

	g->colors[0] = g->config.bg_color;
	g->colors[1] = g->config.frame_color;
	for(i = 0; i < numDataSets; i++ ) {
		g->colors[i+2] = g->config.data_color[i];
	}

	g->timer_index = -1;
	g->draw = FALSE;

	g->main_widget = gtk_vbox_new (FALSE, FALSE);
	gtk_widget_show (g->main_widget);

	g->disp = gtk_drawing_area_new ();
	gtk_widget_set_size_request (g->disp, -1, -1);
	gtk_widget_show (g->disp);

	gtk_widget_set_events (g->disp, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
	gtk_box_pack_start (GTK_BOX (g->main_widget), g->disp, TRUE, TRUE, 0);

	g_signal_connect (G_OBJECT(g->disp), "expose_event", G_CALLBACK (gtkstripchart_expose), g);
	g_signal_connect (G_OBJECT(g->disp), "configure_event", G_CALLBACK (gtkstripchart_configure), g);
	g_signal_connect (G_OBJECT(g->main_widget), "destroy", G_CALLBACK (gtkstripchart_destroy_cb), g);
	g_signal_connect (G_OBJECT(g->main_widget), "button_press_event", G_CALLBACK (gtkstripchart_button_press), g);

	gtkstripchart_alloc (g);

	/****************************
	 * table legend layyout
	 ****************************/
	GtkWidget *color_picker;
	GtkWidget *label;

	g->legendTable = gtk_table_new (g->num_sets, 3, FALSE);
	gtk_box_pack_start (GTK_BOX (g->main_widget), g->legendTable, FALSE, FALSE, 0);

	for( i=0; i < (int)(g->num_sets); i++) {
		g->config.graphColor[i].ind = i;
		g->config.graphColor[i].g   = g;

		color_picker = gnome_color_picker_new ();
		gnome_color_picker_set_i16 (GNOME_COLOR_PICKER (color_picker),
				g->colors[i+2].red,
				g->colors[i+2].green,
				g->colors[i+2].blue, 0);

		g_signal_connect (G_OBJECT (color_picker), "color_set", G_CALLBACK (cb_color_changed), 
				(gpointer)(&(g->config.graphColor[i])) );
		gtk_table_attach (GTK_TABLE (g->legendTable), color_picker, 0, 1, i, i+1, 
				(GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0);

		strcpy( g->dataNames[i], nameArr[i]);
		label = gtk_label_new ( nameArr[i] );
		gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
		gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
		gtk_table_attach (GTK_TABLE (g->legendTable), label, 1, 2, i, i+1, GTK_FILL, (GtkAttachOptions)0, 0, 0);

		g->label[i] = gtk_label_new ("");
		gtk_misc_set_padding (GTK_MISC (g->label[i]), GNOME_PAD_SMALL, 0);
		gtk_misc_set_alignment (GTK_MISC (g->label[i]), 0.0, 0.5);
		gtk_table_attach (GTK_TABLE (g->legendTable), g->label[i], 2, 3, i, i+1, GTK_FILL, (GtkAttachOptions)0, 0, 0);

		if( setType != NULL ) g->paramType[i] = setType[i];
		if( setPtr != NULL )  g->paramPtr[i]  = setPtr[i];
	}

	/****************************
	 * finished
	 ****************************/
	graphCount++;
	gtk_widget_show_all (g->main_widget);
	object_list = g_list_append (object_list, g);

	return g;
}

	void 
gtkstripchart_start (GtkStripChart *g)
{
	if (!g)
		return;

	if (g->timer_index == -1)
		g->timer_index = gtk_timeout_add (g->update_interval, (GtkFunction) gtkstripchart_update, g);

	g->draw = TRUE;
}

	void 
gtkstripchart_stop (GtkStripChart *g)
{
	if (!g)
		return;

	if (g->timer_index > 0)
		gtk_timeout_remove (g->timer_index);
	g->timer_index = -1;
}

/********************************************************************************
 *
 * Callbacks
 *
 ********************************************************************************/
	gint
cb_timeout (gpointer data)
{
	return TRUE;
}

/* probably unnecessary definitions */
#define LEFT_MOUSE 1
#define MIDDLE_MOUSE 2
#define RIGHT_MOUSE 3

	gboolean
gtkstripchart_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
	int button = event->button;
	//int x = (int)(event->x);
	//int y = (int)(event->y);
	GtkStripChart *chart = (GtkStripChart *)user_data;

	//printf("gtkstripchart_button_press: event->type = %i\n", event->type);
	if(button == LEFT_MOUSE) {
		// if a double click then close out waypoint list
		if ( (event->type==GDK_2BUTTON_PRESS || event->type==GDK_3BUTTON_PRESS) ) {
			//printf("gtkstripchart_button_press: double-click\n");
		} else {
			//printf("gtkstripchart_button_press: left-mouse\n");
		}
	} else if (button == RIGHT_MOUSE) {
		//printf("gtkstripchart_button_press: right-mouse chart=%i\n",chart->chartID);
		gtkstripchart_create_preferences_dialog (chart);
	} else if (button == MIDDLE_MOUSE) {
		//printf("gtkstripchart_button_press: middle-mouse\n");
	}
	return FALSE;
}

/********************************************************************************
 *
 * Graph Preferences dialog
 *
 ********************************************************************************/
GtkWidget *prefs_dialog = NULL;

	void
gtkstripchart_create_preferences_dialog (GtkStripChart *chart)
{
	static GtkWidget *dialog = NULL;
	GtkWidget *main_vbox;
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *label;
	GtkAdjustment *adjustment;
	GtkWidget *spin_button;
	GtkWidget *button;
	GtkWidget *cb_legend;
	GtkWidget *cb_legend_table;
	GtkWidget *cb_axis;
	GtkWidget *table;
	GtkWidget *color_picker;
	gfloat update;

	if (prefs_dialog)
		return;

	dialog = gtk_dialog_new_with_buttons ("Preferences", NULL,
			GTK_DIALOG_DESTROY_WITH_PARENT,
			"Apply to ALL", GTK_RESPONSE_APPLY,
			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
			NULL);
	prefs_dialog = dialog;

	//printf("pref dialog: chartID=%i\n", chart->config.chartID);

	main_vbox = GTK_DIALOG (dialog)->vbox;

	frame = gtk_frame_new ("Graphs");
	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, GNOME_PAD_SMALL);

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (frame), vbox);

	hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

	label = gtk_label_new ("Update Speed ( seconds ) :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);

	update = (gfloat) chart->update_interval;
	adjustment = (GtkAdjustment *) gtk_adjustment_new(update / 1000.0, 
			GTKSTRIPCHART_MIN_UPDATE, 
			GTKSTRIPCHART_MAX_UPDATE, 
			GTKSTRIPCHART_MIN_UPDATE, 
			1.0, 0.0);
	spin_button = gtk_spin_button_new (adjustment, 1.0, 2);
	gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);

	button = gtk_button_new_with_mnemonic ("_Set");
	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, GNOME_PAD_SMALL);
	g_object_set_data (G_OBJECT (button), "spin_button", spin_button);
	g_signal_connect (G_OBJECT (button), "clicked",
			G_CALLBACK (update_graph_update_interval), (void*)chart);

	table = gtk_table_new (2, 3, FALSE);
	gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);

	label = gtk_label_new ("Background Color :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
			GTK_FILL, (GtkAttachOptions)0, 0, GNOME_PAD_SMALL);

	color_picker = gnome_color_picker_new ();
	gnome_color_picker_set_i16 (GNOME_COLOR_PICKER (color_picker),
			chart->colors[0].red,
			chart->colors[0].green,
			chart->colors[0].blue, 0);
	g_signal_connect (G_OBJECT (color_picker), "color_set",
			G_CALLBACK (bg_color_changed), (void*)chart);
	gtk_table_attach (GTK_TABLE (table), color_picker, 2, 3, 0, 1,
			(GtkAttachOptions)0, (GtkAttachOptions)0, GNOME_PAD_SMALL, GNOME_PAD_SMALL);

	label = gtk_label_new ("Grid Color :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);

	color_picker = gnome_color_picker_new ();
	gnome_color_picker_set_i16 (GNOME_COLOR_PICKER (color_picker),
			chart->colors[1].red,
			chart->colors[1].green,
			chart->colors[1].blue, 0);
	g_signal_connect (G_OBJECT (color_picker), "color_set",
			G_CALLBACK (frame_color_changed), (void*)chart);
	gtk_table_attach (GTK_TABLE (table), color_picker, 2, 3, 1, 2,
			(GtkAttachOptions)0, (GtkAttachOptions)0, GNOME_PAD_SMALL, GNOME_PAD_SMALL);

	label = gtk_label_new ("Show Table Legend :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);

	cb_legend_table = gtk_check_button_new();
	gtk_widget_show (cb_legend_table);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_legend_table), chart->draw_legend_table);
	gtk_table_attach (GTK_TABLE (table), cb_legend_table, 2, 3, 2, 3,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);
	g_signal_connect (G_OBJECT (cb_legend_table), "toggled", G_CALLBACK (draw_legend_table_toggled), (void*)chart);

	label = gtk_label_new ("Show Legend :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);

	cb_legend = gtk_check_button_new();
	gtk_widget_show (cb_legend);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_legend), chart->draw_legend);
	gtk_table_attach (GTK_TABLE (table), cb_legend, 2, 3, 3, 4,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);
	g_signal_connect (G_OBJECT (cb_legend), "toggled", G_CALLBACK (draw_legend_toggled), (void*)chart);

	label = gtk_label_new ("Axis Mode :");
	gtk_misc_set_padding (GTK_MISC (label), GNOME_PAD_SMALL, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);

	cb_axis = gtk_check_button_new();
	gtk_widget_show (cb_axis);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_axis), chart->config.axisMode);
	gtk_table_attach (GTK_TABLE (table), cb_axis, 2, 3, 4, 5,
			(GtkAttachOptions)(GTK_FILL|GTK_EXPAND), (GtkAttachOptions)(0), 0, GNOME_PAD_SMALL);
	g_signal_connect (G_OBJECT (cb_axis), "toggled", G_CALLBACK (axis_mode_toggled), (void*)chart);

	gtk_widget_show_all (dialog);

	GConfClient *client = guiStr.client;
	char name[128];
	gchar *bg;
	gchar *fg;

	if( gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY ) {
		//cout << "apply to all" << endl;

		sprintf(name, "%s/bg_color", chart->config.gconf_str);
		bg = gconf_client_get_string (client, name, NULL);
		if(bg == NULL ) bg = g_strdup_printf("#%02x%02x%02x", 0xDC, 0xDA, 0xD5);
		sprintf(name, "%s/frame_color", chart->config.gconf_str);
		fg = gconf_client_get_string (client, name, NULL);
		if(fg == NULL) fg = g_strdup_printf("#%02x%02x%02x", 0xFF, 0xFF, 0xFF);

		for(int i=0; i < gtkstripchart_num_charts(); i++) {
			GtkStripChart *g = (GtkStripChart*) g_list_nth_data( object_list, i);
			if( g != NULL && g != chart ) {

				update_graph_update_interval (button, (gpointer)g);

				draw_legend_toggled((GtkToggleButton*)cb_legend, (gpointer)g);
				draw_legend_table_toggled ((GtkToggleButton*)cb_legend_table, (gpointer)g);
				axis_mode_toggled ((GtkToggleButton*)cb_axis, (gpointer)g);

				sprintf(name, "%s/bg_color", g->config.gconf_str);
				gconf_client_set_string (client, name, bg, NULL);

				sprintf(name, "%s/frame_color", g->config.gconf_str);
				gconf_client_set_string (client, name, fg, NULL);
			}
		}
	} 

	gtk_widget_destroy (GTK_WIDGET (dialog));
	prefs_dialog = NULL;
}

	void
prefs_dialog_button_pressed (GtkDialog *dialog, gint id, gpointer data)
{
}

	void
prefs_dialog_apply_to_all(GtkDialog *dialog)
{
}

	void
update_graph_update_interval (GtkWidget *widget, gpointer data)
{
	GtkStripChart *chart = (GtkStripChart*)data;

	GConfClient *client = guiStr.client;

	GtkWidget *spin_button;
	gdouble value = 0;
	char name[256];

	spin_button = (GtkWidget *)g_object_get_data (G_OBJECT (widget), "spin_button");
	value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin_button));

	if (1000 * value == chart->config.update_interval)
		return;

	sprintf (name, "%s/update_interval", chart->config.gconf_str);
	gconf_client_set_int (client, name, (int)(value * 1000), NULL);

	//-- should be handled by gconf
	chart->config.update_interval = MAX( (int)(value * 1000), GTKSTRIPCHART_MIN_UPDATE_MSEC);
	gtkstripchart_stop (chart);
	chart->update_interval = chart->config.update_interval;
	gtkstripchart_start (chart);

}

	void
cb_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b, guint a, gpointer data)
{
	GraphColor *gColor   = (GraphColor*)data;
	GtkStripChart *chart = gColor->g;
	int ind              = gColor->ind;

	if( chart == NULL )
		return;

	GConfClient *client = guiStr.client;
	gchar *color;
	gchar *str;

	r = (guint)(r/0x100);
	g = (guint)(g/0x100);
	b = (guint)(b/0x100);

	printf("cb_color_changed: gconf=%s plot=%i ind=%i\n", chart->config.gconf_str, chart->index, ind);

	color = g_strdup_printf("#%02x%02x%02x", r, g, b);
	str = g_strdup_printf("%s/color_%i", chart->config.gconf_str, ind);
	gconf_client_set_string (client, str, color, NULL);

	g_free (color);
	g_free (str);
}

	void
axis_mode_toggled(GtkToggleButton *togglebutton, gpointer data)
{
	GtkStripChart *chart = (GtkStripChart*)data;
	char name[256];

	int onOff = gtk_toggle_button_get_active(togglebutton);

	GConfClient *client = guiStr.client;
	sprintf(name, "%s/axisMode", chart->config.gconf_str);
	gconf_client_set_int (client, name, onOff, NULL);
}


void
draw_legend_toggled(GtkToggleButton *togglebutton, gpointer data)
{
	//cout << "draw_legend_toggled" << endl;
	GtkStripChart *chart = (GtkStripChart*)data;
	char name[256];

	int onOff = gtk_toggle_button_get_active(togglebutton);

	GConfClient *client = guiStr.client;
	sprintf(name, "%s/draw_legend", chart->config.gconf_str);
	gconf_client_set_int (client, name, onOff, NULL);

	//-- should be handled by gconf
	gtkstripchart_set_legend_draw(chart,  onOff );	
}

void
draw_legend_table_toggled (GtkToggleButton *togglebutton, gpointer data)
{
	GtkStripChart *chart = (GtkStripChart*)data;
	char name[256];

	int onOff = gtk_toggle_button_get_active(togglebutton);
	GConfClient *client = guiStr.client;

	printf("draw_legend_table_toggled: onOff=%i gconf=%s client=%p\n", 
			onOff,
			chart->config.gconf_str, client);

	sprintf(name, "%s/draw_legend_table", chart->config.gconf_str);
	gconf_client_set_int (client, name, onOff, NULL);

	//-- should be handled by gconf
	gtkstripchart_set_legend_table_draw(chart,  onOff );	
}

	void
bg_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b, guint a, gpointer data)
{
	//cout << "bg_color_changed" << endl;
	GtkStripChart *chart = (GtkStripChart*)data;
	char name[256];

	GConfClient *client = guiStr.client;
	gchar *color;

	r = (guint)(r/0x100);
	g = (guint)(g/0x100);
	b = (guint)(b/0x100);

	sprintf(name, "%s/bg_color", chart->config.gconf_str);
	color = g_strdup_printf("#%02x%02x%02x", r, g, b);
	gconf_client_set_string (client, name, color, NULL);

	gdk_color_parse (color, &chart->config.bg_color);
	chart->colors[0] = chart->config.bg_color;
	chart->colors_allocated = FALSE;

	g_free (color);
}

	void
frame_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b, guint a, gpointer data)
{
	//cout << "frame_color_changed" << endl;
	GtkStripChart *chart = (GtkStripChart*)data;
	char name[256];

	GConfClient *client = guiStr.client;
	gchar *color;

	r = (guint)(r/0x100);
	g = (guint)(g/0x100);
	b = (guint)(b/0x100);

	sprintf(name, "%s/frame_color", chart->config.gconf_str);
	color = g_strdup_printf("#%02x%02x%02x", r, g, b);
	gconf_client_set_string (client, name, color, NULL);

	gdk_color_parse (color, &chart->config.frame_color);
	chart->colors[1] = chart->config.frame_color;
	chart->colors_allocated = FALSE;

	g_free (color);
}

	void
timeouts_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
{
	GtkStripChart *g = (GtkStripChart *)data;

#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	GConfValue *value = gconf_entry_get_value (entry);

	g->config.update_interval = 
		MAX( gconf_value_get_int (value), GTKSTRIPCHART_MIN_UPDATE_MSEC);
	gtkstripchart_stop (g);
	g->update_interval = g->config.update_interval;
	gtkstripchart_start (g);

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif
}

	void
axis_mode_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
{
	GtkStripChart *g = (GtkStripChart *)data;

#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	GConfValue *value = gconf_entry_get_value (entry);
	int mode = gconf_value_get_int (value);
	g->config.axisMode = (AXIS_BOUND_MODE)mode;

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif
}

	void
legend_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
{
	//cout<< "legend_changed_cb" << endl;
	GtkStripChart *g = (GtkStripChart *)data;
#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	GConfValue *value = gconf_entry_get_value (entry);
	g->config.draw_legend = gconf_value_get_int (value);
	gtkstripchart_set_legend_draw(g,  gconf_value_get_int (value) );	

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif
}

	void
legend_table_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
{
	//cout << "legend_table_changed_cb" << endl;
	GtkStripChart *g = (GtkStripChart *)data;
	GConfValue *value = gconf_entry_get_value (entry);

#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	int onOff = gconf_value_get_int (value);
	g->config.draw_legend_table = onOff;
	gtkstripchart_set_legend_table_draw(g,  onOff );	

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif
	//cout << "legend_table_changed_cb - exit" << endl;
}

	void
color_changed_cb (GConfClient *client, guint id, GConfEntry *entry, gpointer data)
{
	GtkStripChart *g = (GtkStripChart *)data;
	char name[256];

#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	const gchar *key = gconf_entry_get_key (entry);
	GConfValue *value = gconf_entry_get_value (entry);
	const gchar *color = gconf_value_get_string (value);

	sprintf (name, "%s/bg_color", g->config.gconf_str);
	if (!g_strcasecmp (key, name) ) {
		gdk_color_parse (color, &g->config.bg_color);
		g->colors[0] = g->config.bg_color;
		g->colors_allocated = FALSE;
	} else  {
		sprintf (name, "%s/frame_color", g->config.gconf_str);
		if (!g_strcasecmp (key, name)) {
			gdk_color_parse (color, &g->config.frame_color);
			g->colors[1] = g->config.frame_color;
			g->colors_allocated = FALSE;
		} else {
			int i=0;
			/* loop through data colors */
			for(i=0; i < MAX_NUM_DATA_SETS; i++) {
				sprintf (name, "%s/color_%i", g->config.gconf_str, i);
				if (!g_strcasecmp (key, name)) {
					gdk_color_parse (color, &(g->config.data_color[i]) );
					g->colors[i+2] = g->config.data_color[i];
					g->colors_allocated = FALSE;

#ifdef USE_GDK_THREAD
					// GTK/GDK thread leave
					gdk_flush();
					gdk_threads_leave();
#endif
					return;
				}
			}
		}
	}

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif
}

void gtkstripchart_add_point(GtkStripChart *g, unsigned int dataSet, float val)
{
	if(g == NULL || dataSet < 0 || dataSet >= g->num_sets)
		return;

	int i;
	for (i = g->num_points - 1; i > 0; i--) {
		g->data[i][dataSet] = g->data[i-1][dataSet];
	}
	g->data[0][dataSet] = val;
}

void gtkstripchart_add_all_points(GtkStripChart *g, unsigned int numSets, float *val)
{
	if(g == NULL || numSets < 1 || numSets > g->num_sets || val == NULL)
		return;

	unsigned int i,j;
	for (i = g->num_points - 1; i > 0; i--) {
		for(j=0; j < g->num_sets; j++) {
			g->data[i][j] = g->data[i-1][j];
		}
	}

	for(i=0; i < numSets; i++) {
		g->data[0][i] = val[i];
	}
}

/*
	 char *get_gconf_str(GtkStripChart *g)
	 {
	 if(g == NULL)
	 return NULL;
	 return g->config.gconf_str;
	 }

	 void set_gconf_str(GtkStripChart *g, char *str)
	 {
	 if( g->config.gconf_str )
	 g_free(g->config.gconf_str);
	 g->config.gconf_str = g_strdup(str);		
	 }
	 */

/* Updates the load graph when the timeout expires */
int gtkstripchart_update (GtkStripChart *g)
{
	static float delta = 0.01;
	gchar *text = NULL;

	//cout << "gtkstripchart_update: index=" << g->index  
	//<< " chartID=" << (int)g->config.chartID
	//<< endl;

#ifdef USE_GDK_THREAD
	// GTK/GDK thread enter
	gdk_threads_enter();
#endif

	float tmpVal = NAN;
	/* sawTooth if nothing available */
	if( g->paramPtr[0] == NULL )
	{
		for( unsigned int i=0; i < g->num_sets; i++) {
			tmpVal = g->data[i][0];
			tmpVal += delta;
			if( tmpVal > 1 ) {
				delta = -delta;
				tmpVal = 1;
			} else if( tmpVal < 0 ) {
				delta = -delta;
				tmpVal = 0;
			}

			gtkstripchart_add_point(g, i, tmpVal);
			text = g_strdup_printf (": %g %s", g->data[i][0], "");
			gtk_label_set_text (GTK_LABEL (g->label[i]), text);
			g_free (text);
		}
	} else {
		for( unsigned int i=0; i < g->num_sets; i++) {
			switch( g->paramType[i] ) {
				case CHAR_T: 
					tmpVal = (float) *((char *)(g->paramPtr[i]));
					break;
				case INT8_T: 
					tmpVal = (float) *((int8_t *)(g->paramPtr[i]));
					break;
				case UINT8_T:
					tmpVal = (float) *((uint8_t *)(g->paramPtr[i]));
					break;
				case INT16_T: 
					tmpVal = (float) *((int16_t *)(g->paramPtr[i]));
					break;
				case UINT16_T:
					tmpVal = (float) *((uint16_t *)(g->paramPtr[i]));
					break;
				case INT32_T:
					tmpVal = (float) *((int32_t *)(g->paramPtr[i]));
					break;
				case UINT32_T:
					tmpVal = (float) *((uint32_t *)(g->paramPtr[i]));
					break;
				case INT64_T:
					tmpVal = (float) *((int64_t *)(g->paramPtr[i]));
					break;
				case UINT64_T:
					tmpVal = (float) *((uint64_t *)(g->paramPtr[i]));
					break;
				case FLOAT_T:
					tmpVal = (float) *((float *)(g->paramPtr[i]));
					break;
				case DOUBLE_T:
					tmpVal = (float) *((double *)(g->paramPtr[i]));
					break;
				default:
					cout << "!!!! SHOULD NOT BE HERE !!!!" << endl;
					break;
			}
			gtkstripchart_add_point(g, i, tmpVal);
			text = g_strdup_printf (": %g %s", tmpVal, "");
			gtk_label_set_text (GTK_LABEL (g->label[i]), text);
			g_free (text);
		}
	}

	gtkstripchart_draw (g);

#ifdef USE_GDK_THREAD
	// GTK/GDK thread leave
	gdk_flush();
	gdk_threads_leave();
#endif

	return TRUE;
}

void gconf_getChartConfig(GtkStripChart *g, gchar *set_name)
{
	if(g == NULL)
		return;

	GConfClient *client = guiStr.client;
	GtkStripChartConfig *config = &(g->config);

	char *color=NULL;
	char name[256]={'\0'};
	char base[128]={'\0'};
	int conInd;
	GError *err = NULL;

	if( set_name )
		sprintf(base, "/apps/vcgui/chart/%s", set_name);
	else
		sprintf(base, "/apps/vcgui/chart/%i", g->index);

	config->gconf_str = g_strdup(base);
	//cout << "gconf_str = " << config->gconf_str << endl;
	//cout << "client = " << client << endl;

	sprintf(name, "%s/update_interval", base);
	config->update_interval = gconf_client_get_int (client, name, NULL);
	if( config->update_interval < 100 )
		config->update_interval = 100;
	conInd = gconf_client_notify_add (client, name, timeouts_changed_cb, (void*)g, NULL, &err);
	if( err ) {
		printf( "gconf_getChartConfig - update_interval ERROR: %s", err->message);
	}

	sprintf(name, "%s/bg_color", base);
	color = gconf_client_get_string (client, name, NULL);
	if (!color) color = g_strdup ("#DCDAD5");
	conInd = gconf_client_notify_add (client, name, color_changed_cb, (void*)g, NULL, &err);
	if( err ) {
		printf( "gconf_getChartConfig - update_interval ERROR: %s", err->message);
	}
	gdk_color_parse(color, &(config->bg_color));
	g_free (color);
	color = NULL;

	sprintf(name, "%s/frame_color", base);
	color = gconf_client_get_string (client, name, NULL);
	if (!color) color = g_strdup ("#000000");
	gconf_client_notify_add (client, name, color_changed_cb, (void*)g, NULL, &err);
	if( err ) {
		printf( "gconf_getChartConfig - update_interval ERROR: %s", err->message);
	}
	gdk_color_parse(color, &(config->frame_color));
	g_free (color);
	color = NULL;

	int onOff;
	sprintf(name, "%s/draw_legend_table", base);
	onOff = gconf_client_get_int (client, name, NULL);
	config->draw_legend_table = onOff;
	gconf_client_notify_add (client, name, legend_table_changed_cb, (void*)g, NULL, &err);
	if( err ) {
		printf( "gconf_getChartConfig - update_interval ERROR: %s", err->message);
	}

	sprintf(name, "%s/draw_legend", base);
	onOff = gconf_client_get_int (client, name, NULL);
	config->draw_legend = onOff;
	gconf_client_notify_add (client, name, legend_changed_cb, (void*)g, NULL, &err);
	if( err ) {
		printf( "gconf_getChartConfig - update_interval ERROR: %s", err->message);
	}

	int j;
	for( j=0; j < MAX_NUM_DATA_SETS; j++ ) {
		sprintf(name, "%s/color_%i", base, j);
		color = gconf_client_get_string (client, name, NULL);
		if (!color) color = g_strdup ( DefaultDataColors[j] );
		gconf_client_notify_add (client, name, color_changed_cb, (void*)g, NULL, NULL);
		gdk_color_parse(color, &(config->data_color[j]));
		g_free (color);
		color = NULL;
	}

	sprintf(name, "%s/width", base);
	config->width = gconf_client_get_int (client, name, NULL);
	if( config->width == 0 )
		config->width = 200;

	sprintf(name, "%s/height", base);
	config->height = gconf_client_get_int (client, name, NULL);
	if( config->height == 0 )
		config->height = 130;

	//cout << " width=" << config->width << " height=" << config->height << endl;

	sprintf(name, "%s/axisMode", base);
	config->axisMode = (AXIS_BOUND_MODE)gconf_client_get_int (client, name, NULL);
	gconf_client_notify_add (client, name, axis_mode_changed_cb, (void*)g, NULL, NULL);

	config->update_interval = MAX (config->update_interval, GTKSTRIPCHART_MIN_UPDATE_MSEC);
	config->update_interval = MIN (config->update_interval, 10000);
}

int gtkstripchart_num_charts()
{
	return g_list_length(object_list);
}
